﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.GamerServices;
using ERF;

namespace ERF.Input
{
    public class InputHandler : GameComponent, IInputHandler
    {
        private MouseState oldMouseState;
        private GamePadState oldGamepadState;
        private KeyboardState oldKeyboardState;

        private MouseState mouseState;
        private GamePadState gamepadState;
        private KeyboardState keyboardState;

        private Dictionary<String, List<AssignedButton>> buttonConfig;
        private Dictionary<String, List<AnalogDevice>> deviceConfig;

        private const int KEY_REPEAT = 500;

        public MouseState MouseState {
            get{return mouseState;}
        }
        public MouseState OldMouseState
        {
            get { return oldMouseState; }
        }

        public GamePadState GamepadState {
            get{return gamepadState;}
        }
        public GamePadState OldGamepadState
        {
            get { return oldGamepadState; }
        }
        public KeyboardState KeyboardState {
            get{return keyboardState;}
        }
        public KeyboardState OldKeyboardState
        {
            get { return oldKeyboardState; }
        }

        public InputHandler(ERFGame game) : base(game)
        {
            buttonConfig = new Dictionary<string, List<AssignedButton>>();
            deviceConfig = new Dictionary<string, List<AnalogDevice>>();
        }

        public override void Update(GameTime gameTime)
        {
#if !XBOX
            oldMouseState = mouseState;
            mouseState = Mouse.GetState();

            oldKeyboardState = keyboardState;
            keyboardState = Keyboard.GetState();
#endif
            oldGamepadState = gamepadState;
            gamepadState = GamePad.GetState(PlayerIndex.One);

            base.Update(gameTime);
        }

        public bool IsButtonDown(String command, GameTime gameTime)
        {
            return IsButtonDown(command, gameTime, false);
        }

        public bool IsButtonDown(String command, GameTime gameTime, bool acceptRepeat)
        {
            if (buttonConfig.ContainsKey(command))
            {
                foreach (AssignedButton button in buttonConfig[command])
                {
                    if (button.IsButtonDown())
                    {
                        if (acceptRepeat)
                        {
                            if ((gameTime.TotalGameTime - button.LastUsedTime).TotalMilliseconds >= KEY_REPEAT)
                            {
                                return true;
                            }
                        }
                        else
                            return true;

                        button.LastUsedTime = gameTime.TotalGameTime;
                    }
                }
            }
            return false;
        }

        public bool IsButtonReleased(String command)
        {
            if (buttonConfig.ContainsKey(command))
            {
                foreach (AssignedButton button in buttonConfig[command])
                {
                    if (button.IsButtonReleased())
                        return true;
                }
            }
            return false;
        }

        public Vector2 GetDeviceLocation(String command)
        {
            List<AnalogDevice> devices = new List<AnalogDevice>();

            if (deviceConfig.TryGetValue(command, out devices))
            {
                foreach (AnalogDevice device in devices)
                {
                    if (device.Location.Length() != 0)
                        return device.Location;
                }
            }

            return Vector2.Zero;
        }

        public void AssignButton(String command, AssignedButton button)
        {
            if (!buttonConfig.ContainsKey(command))
            {
                buttonConfig[command] = new List<AssignedButton>();
            }
            
            buttonConfig[command].Add(button);
        }

        public void AssignDevice(String command, AnalogDevice device)
        {
            if (!deviceConfig.ContainsKey(command))
            {
                deviceConfig[command] = new List<AnalogDevice>();
            }
            deviceConfig[command].Add(device);
        }

        public void DeleteButton(String command, AssignedButton button)
        {
            if (buttonConfig.ContainsKey(command))
            {
                buttonConfig[command].Remove(button);
            }
        }

        public void DeleteDevice(String command, AnalogDevice device)
        {
            if (deviceConfig.ContainsKey(command))
            {
                deviceConfig[command].Remove(device);
            }
        }
    }
}
